/// @tags: ACAutoMaton SegmentTree Multiplation
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>

using namespace std;

namespace BlueQuantum {

int const N = 1e5 + 5, M = 26, T = 55, BIT = 19;

int tot, e_cnt, pos;
char t[T], s[N];
int ch[N][M];
int siz[55], lg[N * 4], tag[N * 4], sta[N], len[N];

struct Node {
  int pos[T], val[T];

  inline Node operator+(Node const &rhs) const {
    Node res;
    for (int i = 0; i <= tot; ++i)
      res.pos[i] = rhs.pos[pos[i]], res.val[i] = rhs.val[pos[i]] + val[i];
    return res;
  }

  inline static Node init(int c) {
    Node res;
    for (int i = 0; i <= tot; ++i) res.pos[i] = ch[i][c], res.val[i] = siz[ch[i][c]];
    return res;
  }
} tr[N * 4], g[N * BIT * 2], *node[N][BIT];

inline void pushup(int x) { tr[x] = tr[x << 1] + tr[x << 1 | 1]; }

void build(int x, int l, int r) {
  if (l == r) {
    tr[x] = Node::init(s[l] - 'a');
    return;
  }
  int mid = (l + r) >> 1;
  build(x << 1, l, mid), build(x << 1 | 1, mid + 1, r);
  pushup(x);
}

inline void update(int x, int id, int l, int r) {
  int now = lg[r - l + 1], pos = (l - sta[id]) % len[id];
  tag[x] = id, tr[x] = node[id][now][pos];
}

inline void pushdown(int x, int l, int r) {
  if (tag[x]) {
    int mid = (l + r) >> 1;
    update(x << 1, tag[x], l, mid);
    update(x << 1 | 1, tag[x], mid + 1, r);
    tag[x] = 0;
  }
}

void modify(int x, int l, int r, int L, int R, int id) {
  if (L <= l && r <= R) return update(x, id, l, r);
  pushdown(x, l, r);
  int mid = (l + r) >> 1;
  if (L <= mid) modify(x << 1, l, mid, L, R, id);
  if (mid < R) modify(x << 1 | 1, mid + 1, r, L, R, id);
  pushup(x);
}

int query(int x, int l, int r, int L, int R) {
  if (L <= l && r <= R) {
    int res = tr[x].val[pos];
    pos = tr[x].pos[pos];
    return res;
  }
  pushdown(x, l, r);
  int mid = (l + r) >> 1, res = 0;
  if (L <= mid) res = query(x << 1, l, mid, L, R);
  if (mid < R) res += query(x << 1 | 1, mid + 1, r, L, R);
  return res;
}

inline void insert(char str[]) {
  int len = strlen(str), cur = 0;
  for (int i = 0; i < len; ++i) {
    int c = str[i] - 'a';
    if (ch[cur][c] == 0) ch[cur][c] = ++tot;
    cur = ch[cur][c];
  }
  siz[cur]++;
}

inline void getF() {
  static int f[N];
  queue<int> q;
  for (int i = 0; i < M; ++i)
    if (ch[0][i]) q.push(ch[0][i]);
  while (!q.empty()) {
    int u = q.front();
    q.pop();
    for (int i = 0; i < M; ++i) {
      int v = ch[u][i];
      v ? (q.push(v), f[v] = ch[f[u]][i], siz[v] += siz[f[v]]) : ch[u][i] = ch[f[u]][i];
    }
  }
}

inline int main() {
  int n, q;
  cin >> n >> q;
  for (int i = 1; i <= n; ++i) {
    cin >> t;
    insert(t);
  }
  getF();
  cin >> (s + 1);
  int slen = strlen(s + 1);
  int maxl = 1;
  while (maxl <= slen) maxl <<= 1;
  for (int i = 2; i <= maxl; i++) lg[i] = lg[i >> 1] + 1;
  build(1, 1, maxl);
  Node *cur = g;
  static char str[N];
  for (int i = 1, opt, l, r, cnt = 0; i <= q; ++i) {
    cin >> opt >> l >> r;
    switch (opt) {
      case 1:
        cin >> str;
        cnt++, sta[cnt] = l, len[cnt] = strlen(str);
        node[cnt][0] = cur;
        for (int j = 0; j < len[cnt]; ++j) *cur = Node::init(str[j] - 'a'), ++cur;
        for (int j = 1; j < BIT; ++j) {
          node[cnt][j] = cur;
          for (int k = 0; k < len[cnt]; ++k) {
            *cur =
                node[cnt][j - 1][k] + node[cnt][j - 1][(k + (1 << (j - 1))) % len[cnt]],
            ++cur;
          }
        }
        modify(1, 1, maxl, l, r, cnt);
        break;
      case 2:
        pos = 0;
        cout << query(1, 1, maxl, l, r) << '\n';
    }
  }
  return 0;
}

}  // namespace BlueQuantum

int main() {
#ifndef ONLINE_JUDGE
#ifdef LOCAL
  freopen("/tmp/CodeTmp/testdata.in", "r", stdin);
  freopen("/tmp/CodeTmp/testdata.out", "w", stdout);
#else
  freopen("str.in", "r", stdin);
  freopen("str.out", "w", stdout);
#endif
#endif

  ios::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
  return BlueQuantum::main();
}
